package cn.kginglam.dynamic_excel.excel.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.kginglam.dynamic_excel.common.utils.ReflectUtils;
import cn.kginglam.dynamic_excel.excel.annotation.ExcelHeadAlias;
import cn.kginglam.dynamic_excel.excel.option.AbstractOption;
import com.sun.istack.internal.NotNull;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author: Lam
 * @date: 2021-09-03 09:58
 * @description:
 */
public class DynamicExcelUtils {

    /**
     * @param list         数据源
     * @param option       选项（自定义head）
     * @param outputStream
     * @param <T>
     * @param <S>
     */
    public static <T, S extends AbstractOption> void export(@NotNull List<T> list, @NotNull S option, @NotNull HttpServletResponse outputStream) {

        synchronized (option) {
            if (CollectionUtil.isEmpty(list)) {
                return;
            }

            // 反射获取 option（选项器）的属性
            Field[] fields = option.getClass().getDeclaredFields();


            // 提取 option（选项器）的属性的 @ExcelHeadAlias 信息
            List<ExcelHeadAlias> excelHeadAliasList =
                    Arrays.stream(fields)
                            .map(field -> DynamicExcelUtils.extractExcelHeadAlias(option, field))
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());


            DynamicExcelUtils.analysisHeadAndData(excelHeadAliasList, list, outputStream);
        }
    }


    /**
     * 解析Excel头部和数据
     *
     * @param excelHeadAliasList
     * @param dataList
     * @param outputStream
     * @param <T>
     */
    private static <T> void analysisHeadAndData(List<ExcelHeadAlias> excelHeadAliasList, List<T> dataList, HttpServletResponse outputStream) {

        // 需要映射的属性
        List<String> attributeList = excelHeadAliasList.stream().map(ExcelHeadAlias::attribute).collect(Collectors.toList());


        // 映射数据
        List<List<Object>> attributeValueList = dataList.stream().map(data -> attributeList.stream().map(attribute -> {

            Field f = Arrays.stream(data.getClass().getDeclaredFields())
                    .filter(field -> ObjectUtil.equals(field.getName(), attribute))
                    .findFirst().filter(ObjectUtil::isNotNull).get();

            return ReflectUtils.invokeGet(data, f.getName());
        }).collect(Collectors.toList())).collect(Collectors.toList());


        // 表头
        List<List<String>> excelAliasList =
                excelHeadAliasList.stream().map(excelHeadAlias -> Collections.singletonList(excelHeadAlias.alias())).collect(Collectors.toList());


        ExcelUtil.writeExcel(outputStream, "测试名称", "测试sheet", excelAliasList, attributeValueList);
    }


    /**
     * 提取 option（选项器）的属性的 @ExcelHeadAlias 信息
     *
     * @param option
     * @param field
     * @param <T>
     * @param <S>
     * @return
     */
    private static <T, S extends AbstractOption> ExcelHeadAlias extractExcelHeadAlias(@NotNull S option, @NotNull Field field) {
        // 获取属性值
        Integer flag = (Integer) ReflectUtils.invokeGet(option, field.getName());

        // 如果当前属性值 == null || 当前属性值标记为不需要导出
        if (ObjectUtil.isNull(flag) || NumberUtil.equals(flag, AbstractOption.UN_OPT_EXPORT_FLAG)) return null;

        // 获取当前属性值的 @ExcelHeadAlias 注解
        return field.getAnnotation(ExcelHeadAlias.class);
    }
}


